////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef __WN_MATH_INTERNAL_ARM_BASIC_INL__
#define __WN_MATH_INTERNAL_ARM_BASIC_INL__

#ifndef __WN_MATH_BASIC_H__
    #error "Internal/ARM/WNBasic.inl should never be included directly. Please include WNBasic.h instead"
#elif !defined _WN_ARM
    #error "Internal/ARM/WNBasic.inl has been included on a non ARM platform. Please rectify this."
#elif !defined __WN_MATH_ENABLE_EXTENSIONS
    #error "Internal/ARM/WNBasic.inl has been included when extensions are disabled. Please rectify this."
#endif

#ifdef __WN_MATH_NEON_ALLOWED
    #ifdef _WN_GNUC
        #include "WNMath/inc/Internal/ARM/NEON/gnuc/WNBasic.inl"
    #else
        #include "WNMath/inc/Internal/ARM/NEON/WNBasic.inl"
    #endif
#endif

#ifdef __WN_MATH_ALLOW_RUNTIME
    #include "WNCore/inc/WNSystem.h"
#endif

namespace WNMath {
    template <>
    WN_FORCE_INLINE WN_FLOAT32 WNRound(const WN_FLOAT32& _number) {
        #ifdef __WN_MATH_NEON_FORCED
            return(__WNInternal::__WNRoundNEON(_number));
        #else
            #ifdef __WN_MATH_NEON_ALLOWED
                if (WNCore::WNSystem::WNHasNEON()) {
                    return(__WNInternal::__WNRoundNEON(_number));
                }
            #endif

            return(__WNInternal::__WNRoundGeneric(_number));
        #endif
    }

    template <>
    WN_FORCE_INLINE WN_FLOAT32 WNCeil(const WN_FLOAT32& _number) {
        #ifdef __WN_MATH_NEON_FORCED
            return(__WNInternal::__WNCeilNEON(_number));
        #else
            #ifdef __WN_MATH_NEON_ALLOWED
                if (WNCore::WNSystem::WNHasNEON()) {
                    return(__WNInternal::__WNCeilNEON(_number));
                }
            #endif

            return(__WNInternal::__WNCeilGeneric(_number));
        #endif
    }

    template <>
    WN_FORCE_INLINE WN_FLOAT32 WNFloor(const WN_FLOAT32& _number) {
        #ifdef __WN_MATH_NEON_FORCED
            return(__WNInternal::__WNFloorNEON(_number));
        #else
            #ifdef __WN_MATH_NEON_ALLOWED
                if (WNCore::WNSystem::WNHasNEON()) {
                    return(__WNInternal::__WNFloorNEON(_number));
                }
            #endif

            return(__WNInternal::__WNFloorGeneric(_number));
        #endif
    }

    template <>
    WN_FORCE_INLINE WN_FLOAT32 WNTrunc(const WN_FLOAT32& _number) {
        #ifdef __WN_MATH_NEON_FORCED
            return(__WNInternal::__WNTruncNEON(_number));
        #else
            #ifdef __WN_MATH_NEON_ALLOWED
                if (WNCore::WNSystem::WNHasNEON()) {
                    return(__WNInternal::__WNTruncNEON(_number));
                }
            #endif

            return(__WNInternal::__WNTruncGeneric(_number));
        #endif
    }

    template <>
    WN_FORCE_INLINE WN_FLOAT32 WNSqrt(const WN_FLOAT32& _number) {
        #ifdef __WN_MATH_NEON_FORCED
            return(__WNInternal::__WNSqrtNEON(_number));
        #else
            #ifdef __WN_MATH_NEON_ALLOWED
                if (WNCore::WNSystem::WNHasNEON()) {
                    return(__WNInternal::__WNSqrtNEON(_number));
                }
            #endif

            return(__WNInternal::__WNSqrtGeneric(_number));
        #endif
    }

    template <>
    WN_FORCE_INLINE WN_FLOAT32 WNInvSqrt(const WN_FLOAT32& _number) {
        #ifdef __WN_MATH_NEON_FORCED
            return(__WNInternal::__WNInvSqrtNEON(_number));
        #else
            #ifdef __WN_MATH_NEON_ALLOWED
                if (WNCore::WNSystem::WNHasNEON()) {
                    return(__WNInternal::__WNInvSqrtNEON(_number));
                }
            #endif

            return(__WNInternal::__WNInvSqrtGeneric(_number));
        #endif
    }
}

#endif // __WN_MATH_INTERNAL_ARM_BASIC_INL__